#!/bin/bash

CUR_PATH=`pwd`
FABRIC_SDK_PATH="$CUR_PATH/fabric-sdk"
CHAINCODE_NAME="mycc"
CHANNELS=("mychannelone" "mychanneltwo")
# CHANNELS=("mychannelone")

source /etc/profile
source cluster_IP.conf

usage="usage: $0 -b/--branch <branch>\n"
usage=$usage"\t-b, --branch: fabric sdk branch which deploy\n"

usage_exit() {
    printf "$usage"
    exit
}

function wait_sometime() {
    for((i=1; i<=$1; i++))
    do
        sleep 1s
        echo "wait ${i}s ..."
    done
}

function update_fabric_sdk() {
    echo "update fabric-sdk for all nodes ... "
    for node in ${FABRIC_PEER0_IP[@]} ${FABRIC_PEER1_IP[@]} ${FABRIC_ORDERER_IP[@]}
    do
        ssh $node "
            # source /etc/profile
            cd $FABRIC_SDK_PATH
            git pull
        " &
    done 
    wait
    echo "update fabric-sdk for all nodes ... done"
}

function config_hosts_for_nodes() {
    echo -n "config hosts for all nodes ... "
    for node in ${FABRIC_PEER0_IP[@]} ${FABRIC_PEER1_IP[@]} ${FABRIC_ORDERER_IP[@]}
    do
        ssh $node "cd $FABRIC_SDK_PATH; ./hosts_config.sh > /dev/null 2>&1" &
    done
    wait
    echo "done"
}

function start_fabric_cluster() {
    echo "start fabric network"

    i=1
    for node in ${FABRIC_PEER0_IP[@]}
    do
        ssh $node " export IMAGE_TAG='latest'
                    export COMPOSE_PROJECT_NAME='net'
                    source $CUR_PATH/cluster_IP.conf
                    cd $FABRIC_SDK_PATH/compose-up
                    docker-compose -f docker-compose-org${i}-peer0.yaml up -d
        " &
        let i=i+1
    done

    i=1
    for node in ${FABRIC_PEER1_IP[@]}
    do
        ssh $node " export IMAGE_TAG='latest'
                    export COMPOSE_PROJECT_NAME='net'
                    source $CUR_PATH/cluster_IP.conf
                    cd $FABRIC_SDK_PATH/compose-up
                    docker-compose -f docker-compose-org${i}-peer1.yaml up -d
        " &
        let i=i+1
    done

    i=1
    for node in ${FABRIC_ORDERER_IP[@]}
    do
        ssh $node " export IMAGE_TAG='latest'
                    export COMPOSE_PROJECT_NAME='net'
                    source $CUR_PATH/cluster_IP.conf
                    cd $FABRIC_SDK_PATH/compose-up
                    docker-compose -f docker-compose-order${i}.yaml up -d
        " &
        let i=i+1
    done

    wait
    echo "finish start fabric network!"
}

function gen_join_channel_installCC() {
    CHANNEL_NAME=${CHANNELS[$1]}
    let j=$1+1
    ORDERER="orderer${j}.demo.com"
    
    if [[ $1 == "0" ]]; then
        PEER_IP=("${FABRIC_PEER0_IP[@]}")
    elif  [[ $1 == "1" ]]; then
        PEER_IP=("${FABRIC_PEER1_IP[@]}")
    else
        echo "invalid channel ID, expect: 0 or 1"
    fi
    # echo $CHANNEL_NAME $ORDERER

    # generate channel
    docker exec cli peer channel create -o ${ORDERER}:7050 -c ${CHANNEL_NAME} -f ./channel-artifacts/${CHANNEL_NAME}.tx \
    --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/${ORDERER}/msp/tlscacerts/tlsca.demo.com-cert.pem
    if [ $? -ne 0 ]; then
        return -1
    fi

    # copy to local host
    docker cp cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/${CHANNEL_NAME}.block $FABRIC_SDK_PATH/compose-up/${CHANNEL_NAME}.block

    # copy ${CHANNEL_NAME}.block to docker containers & join for cli{0..1}/peer{0..1}.org{1..4}.demo.com
    for ((i=0; i<${#PEER_IP[@]}; i++))
    do
        let j=i+1
        scp $FABRIC_SDK_PATH/compose-up/${CHANNEL_NAME}.block ${PEER_IP[$i]}:$FABRIC_SDK_PATH/compose-up/${CHANNEL_NAME}.block
        ssh ${PEER_IP[$i]} "
            docker cp $FABRIC_SDK_PATH/compose-up/${CHANNEL_NAME}.block cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/${CHANNEL_NAME}.block
            docker exec cli peer channel join -b ${CHANNEL_NAME}.block
            docker exec cli peer channel update -o ${ORDERER}:7050 -c ${CHANNEL_NAME} -f ./channel-artifacts/Org${j}MSPanchors_${CHANNEL_NAME}.tx --tls \
            --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/${ORDERER}/msp/tlscacerts/tlsca.demo.com-cert.pem
        " &
    done
    wait

    # chaincode exists ?
    cd $FABRIC_SDK_PATH/chaincode/go/
    if [ ! -f "objhash_chaincode.go" ]; then
        echo "no chaincode exist, please put chaincode to $(pwd)"
        exit -1
    fi

    # install chaincode for all peers
    for ((i=0; i<${#PEER_IP[@]}; i++))
    do
        ssh ${PEER_IP[$i]} "
            docker exec cli peer chaincode install -n ${CHAINCODE_NAME} -p github.com/chaincode/go/ -v 1.0
        " &
    done
    wait

    # instantiate chaincode
    ssh ${PEER_IP[0]} "
        docker exec cli peer chaincode instantiate -o ${ORDERER}:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/${ORDERER}/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -v 1.0 -c '{\"Args\":[\"init\"]}' -P 'OR (\"Org1MSP.member\", \"Org2MSP.member\", \"Org3MSP.member\", \"Org4MSP.member\")'
        # docker exec cli peer chaincode instantiate -o ${ORDERER}:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/${ORDERER}/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -v 1.0 -c '{\"Args\":[\"init\"]}' -P 'OutOf(3, \"Org1MSP.member\", \"Org2MSP.member\", \"Org3MSP.member\", \"Org4MSP.member\")'
    "

    # wait a few time for chaincode instantiate
    wait_sometime 3

    # run chaincode in other cluster
    for ((i=1; i<${#PEER_IP[@]}; i++))
    do
        ssh ${PEER_IP[$i]} "
            docker exec cli peer chaincode invoke -o ${ORDERER}:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/${ORDERER}/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -c '{\"Args\":[\"create\",\"obj_${i}\",\"123\"]}'
        " &
    done
    wait

    # test query
    ssh ${PEER_IP[0]} "
        # docker exec cli peer chaincode invoke -o ${ORDERER}:7050  --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/${ORDERER}/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -c '{\"Args\":[\"create\",\"obj_0\",\"123\"]}'
        docker exec cli peer chaincode query -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -c '{\"Args\":[\"read\",\"object_0\"]}'
    "
    return 0
}


if [ $# -ne 0 ]; then
    usage_exit
fi

# GOPATH exist ?
if [ 0"$GOPATH" = "0" ]; then
    echo "GOPATH not exist, please install go and set it"
    exit -1
fi

# crypto config files exist ?
cd $FABRIC_SDK_PATH/compose-up
if [[ ! -d "channel-artifacts" || ! -d "crypto-config" ]]; then
    echo "'crypto-config' & 'channel-artifacts' not exist"
    echo "please gen-crypto by hand && push it to fabric-sdk"
    exit -1
fi

# update fabric-sdk to all nodes
update_fabric_sdk

# config hosts in every node
config_hosts_for_nodes

# down & remove fabric containers may exist
cd $CUR_PATH
./down_fabric_cluster.sh

# start fabric network
start_fabric_cluster

# # wait or a few time wait raft leader election
# wait_sometime 5

# generate & join channel for all peers
for ((i=0; i<${#CHANNELS[@]}; i++))
do
    gen_join_channel_installCC $i &&
    if [ $? -ne 0 ]; then
        echo "generate & join channel $i error"
        exit -1
    fi &
done
wait

echo "deploy fabric finish"
